package com.morpheus.redis.redisson.api.guid;

import java.util.LinkedHashMap;
import java.util.Map;
import java.util.concurrent.TimeUnit;

import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.support.atomic.RedisAtomicLong;

public class RedisGuidUtil {
	private static final Logger LOGGER = LoggerFactory.getLogger(RedisGuidUtil.class);
	private static final Integer DATA_SIZE = 32;
	private static final String[] RADIX_STR = new String[] { "0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "a", "b",
			"c", "d", "e", "f", "g", "h", "i", "j", "k", "l", "m", "n", "o", "p", "q", "r", "s", "t", "u", "v" };
	public static final String SNOW = "snowId";
	private static Map<String, Integer> RADIX_MAP = new LinkedHashMap<>();

	static {
		for (int i = 0; i < DATA_SIZE; i++) {
			RADIX_MAP.put(RADIX_STR[i], i);
		}
	}

	private RedisGuidUtil() {
	}

	/**
	 * 获取单个全局Id
	 * @param redisTemplate
	 * @param appName
	 * @return
	 */
	public static long nextId(RedisTemplate<?, ?> redisTemplate, String appName) {
		String key = RedisGuidUtil.SNOW + appName;
		RedisAtomicLong redisAtomicLong = new RedisAtomicLong(key, redisTemplate.getConnectionFactory());
		long andIncrement = redisAtomicLong.getAndIncrement();
		// result在0~1023之间
		long result = andIncrement % (DATA_SIZE * DATA_SIZE);
		// 将result转化为32进制数，个位为worlId，十位为dataId
		String strResult = Integer.toString(Math.toIntExact(result), DATA_SIZE);
		String strResult2 = StringUtils.leftPad(strResult, 2, "0");
		String substring1 = strResult2.substring(0, 1);
		String substring2 = strResult2.substring(1, 2);
		Integer dataId = RADIX_MAP.get(substring1);
		Integer workId = RADIX_MAP.get(substring2);
		SnowIdDTO snowIdDTO = new SnowIdDTO(System.currentTimeMillis(), dataId, workId);
		long id = snowIdDTO.getId();
		return id;
	}

	/**
	 * 批量获取全局Id(雪花算法)
	 * @param redisTemplate
	 * @param appName
	 * @param batchSize
	 * @return
	 */
	public static long[] nextId(RedisTemplate<?, ?> redisTemplate, String appName, int batchSize) {
		long[] resultIds = new long[batchSize];
		String key = RedisGuidUtil.SNOW + appName;
		RedisAtomicLong redisAtomicLong = new RedisAtomicLong(key, redisTemplate.getConnectionFactory());
		int pageSize = 1024;
		int pageCount = Double.valueOf(Math.ceil(batchSize * 1.0 / pageSize)).intValue();
		for (int pageNo = 1; pageNo <= pageCount; pageNo++) {
			long timestamp = System.currentTimeMillis();
			int limit = Math.min(pageNo * pageSize, batchSize);
			for (int idx = (pageNo - 1) * pageSize; idx < limit; idx++) {
				long andIncrement = redisAtomicLong.getAndIncrement();
				// result在0~1023之间
				long result = andIncrement % (DATA_SIZE * DATA_SIZE);
				// 将result转化为32进制数，个位为worlId，十位为dataId
				String strResult = Integer.toString(Math.toIntExact(result), DATA_SIZE);
				String strResult2 = StringUtils.leftPad(strResult, 2, "0");
				String substring1 = strResult2.substring(0, 1);
				String substring2 = strResult2.substring(1, 2);
				Integer dataId = RADIX_MAP.get(substring1);
				Integer workId = RADIX_MAP.get(substring2);
				SnowIdDTO snowIdDTO = new SnowIdDTO(timestamp, dataId, workId);
				resultIds[idx] = snowIdDTO.getId();
			}
			try {
				TimeUnit.MILLISECONDS.sleep(300);
			} catch (Throwable th) {
				LOGGER.error("RedisGuidUtil.nextId()", th);
			}
		}
		return resultIds;
	}
}
